package handlers

import (
	"bloggo/bloggo"
	"bloggo/dto"
	"bloggo/service"
	"bloggo/structs"
	"context"
	"fmt"
	"gitee.com/chunanyong/zorm"
	"github.com/gin-gonic/gin"
	"strconv"
	"time"
)

// Tags 标签
func Tags(c *gin.Context) *bloggo.R {
	page := zorm.NewPage()
	page.PageNo, _ = strconv.Atoi(c.DefaultQuery("current", "1"))
	page.PageSize, _ = strconv.Atoi(c.DefaultQuery("size", "20"))
	keywords := c.DefaultQuery("keywords", "")
	finder := zorm.NewFinder()
	finder.Append("SELECT * FROM").Append(structs.TbTagStructTableName)
	finder.Append("WHERE 1=1")
	if len(keywords) > 0 {
		finder.Append("AND tag_name LIKE ?", "%"+keywords+"%")
	}
	finder.Append(" ORDER BY id ASC ")
	var tagDTO []dto.TagDTO
	err := zorm.Query(c, finder, &tagDTO, page)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	var tagIds []int
	for i := range tagDTO {
		tagIds = append(tagIds, tagDTO[i].Id)
	}
	tagsArticleCount := TagsArticleCount(tagIds)
	if len(tagsArticleCount) > 0 {
		for i := range tagDTO {
			tagDTO[i].ArticleCount = tagsArticleCount[tagDTO[i].Id]
		}
	}

	return bloggo.OkData(gin.H{
		"recordList": tagDTO,
		"count":      page.TotalCount,
	})
}

// TagsSearch 标签列表搜索
func TagsSearch(c *gin.Context) *bloggo.R {
	keywords := c.DefaultQuery("keywords", "")

	finder := zorm.NewFinder()
	finder.Append("SELECT * FROM").Append(structs.TbTagStructTableName)
	finder.Append("WHERE tag_name LIKE ?", fmt.Sprint("%", keywords, "%"))
	finder.Append("ORDER BY id ASC")
	var tagDTO []dto.TagDTO
	err := zorm.Query(c, finder, &tagDTO, nil)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	return bloggo.OkData(tagDTO)
}

// SaveTag 保存标签
func SaveTag(c *gin.Context) *bloggo.R {
	var reqData dto.TagDTO
	err := c.ShouldBind(&reqData)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	var tagStruct structs.TbTagStruct
	tagStruct.Id = reqData.Id
	tagStruct.TagName = reqData.TagName
	tagStruct.UpdateTime = time.Now()
	if reqData.Id == 0 { //insert
		tagStruct.CreateTime = time.Now()
		err = service.SaveTbTagStruct(c, &tagStruct)
	} else { //update
		err = service.UpdateNotZeroTbTagStruct(c, &tagStruct)
	}
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	return bloggo.Ok()
}

// FetchDeleteTag 批量删除标签
func FetchDeleteTag(c *gin.Context) *bloggo.R {
	var ids []int
	err := c.ShouldBind(&ids)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	if len(ids) == 0 {
		return bloggo.Ok()
	}
	var count int
	finder := zorm.NewSelectFinder(structs.TbArticleTagStructTableName, "count(*)")
	finder.Append("WHERE tag_id IN (?)", ids)
	_, err = zorm.QueryRow(c, finder, &count)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	if count > 0 {
		return bloggo.FailMessage("删除失败，该标签下存有文章")
	}
	updateCount, err := zorm.Transaction(c, func(ctx context.Context) (interface{}, error) {
		finder := zorm.NewDeleteFinder(structs.TbTagStructTableName)
		finder.Append("WHERE id IN (?)", ids)
		updateCount, err2 := zorm.UpdateFinder(ctx, finder)
		if err2 != nil {
			return nil, err2
		}
		return updateCount, nil
	})
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	return bloggo.OkData(updateCount)
}

// TagsArticleCount 获取标签的文章数量
func TagsArticleCount(tagIds []int) map[int]int64 {
	var rm = make(map[int]int64)
	if len(tagIds) == 0 {
		return rm
	}
	finder := zorm.NewSelectFinder(structs.TbArticleTagStructTableName, "tag_id ,count(*) AS articleCount")
	finder.Append("WHERE tag_id IN (?)", tagIds)
	finder.Append("GROUP BY tag_id")

	queryMap, err := zorm.QueryMap(context.Background(), finder, nil)
	if err != nil {
		panic(err)
	}
	for _, v := range queryMap {
		rm[v["tag_id"].(int)] = v["articleCount"].(int64)
	}
	return rm
}
